<script setup lang="ts">
import type { Ref } from 'vue'

import type { CascaderDiff, CascaderUpdateModel } from '.'
import type {
  CascaderNodeModel,
  CdnCascaderProps,
} from '@/components/Cascader/types'

import { useFullscreen } from '@vueuse/core'

import LevelCard from './components/LevelCard.vue'
import { NodeEmptyTipsProvideKey } from './config'
import { defaultEmptyTips } from './constants/defaultValue'
import { useBuildData } from './hooks/useBuildData'
import { useCascaderStore } from './hooks/useCascaderStore'
import { useWatchElement } from './hooks/useWatchElement'
import './styles'

interface IEmits {
  (event: 'nodeClick', isChanged: boolean, node: CascaderNodeModel): void
}
const props = withDefaults(defineProps<CdnCascaderProps>(), {
  data: () => ({ charts: [] }),
})
const emit = defineEmits<IEmits>()
const modelValue = ref<CascaderUpdateModel>()
const diffValue = defineModel<CascaderDiff[]>('diff')
const tipsValue = inject('tipsValue') as Ref<{
  error: number
  warning: number
  risks: string[]
}>

const { dataSource, doLayout } = useBuildData(toRef(props, 'data'))

const emptyTips = computed(() =>
  Object.assign({}, defaultEmptyTips, props?.nodeEmptyTips || {}),
)

const { diff } = useCascaderStore()
const cdnCascaderEl = ref<HTMLElement>()

useWatchElement({
  el: cdnCascaderEl,
  className: 'node-sortable-ghost',
  specifiedClass: 'is-sortable',
})

provide(NodeEmptyTipsProvideKey, emptyTips)

function updateModelValue() {
  const data = dataSource.value!.charts!
  modelValue.value = data
}

function updateTipsValue() {
  tipsValue.value = (dataSource.value?.charts || []).reduce(
    (acc, item) => {
      if (!item?.node_L1?.length) {
        acc.error += 1
        acc.risks.push(`【${item.region_name}】 缺少 L1层级，请求将无法解析`)
      } else if (!item?.node_L2?.length) {
        acc.warning += 1
        acc.risks.push(
          `【${item.region_name}】 缺少 L2 层级节点，L1 层级节点直接向源站回源`,
        )
      }
      return acc
    },
    { warning: 0, error: 0, risks: [] as string[] },
  )!
}

watchPostEffect(() => {
  diffValue.value = diff.value
  updateModelValue()
  updateTipsValue()
})

const { enter, exit, toggle } = useFullscreen(cdnCascaderEl)

function position(type?: 'error' | 'warning') {
  const el = cdnCascaderEl.value?.querySelector(
    type ? `.cascader-level-card--${type}` : '.cascader-level-card--tips',
  )
  el?.scrollIntoView?.({
    behavior: 'smooth',
  })
}
const isConfirm = computed(() => {
  const isDiff = diff.value.some(obj =>
    ['LEVEL', 'REGION', 'REGION_LEVEL'].includes(obj.diffType),
  )

  const tipsDiff = tipsValue.value?.risks && tipsValue.value.risks.length > 0

  return isDiff || tipsDiff
})

const disabled = computed(() => diff.value.length === 0)

defineExpose({
  // isFullscreen,
  enter,
  exit,
  toggle,
  position,
  modelValue,
  isConfirm,
  disabled,
  doLayout,
})

const scrollRef = ref()
const wrapWidth = ref(0)
provide('cascadeWrapWidth', wrapWidth)
function calcWrapWidth() {
  if (!scrollRef.value) {
    return
  }
  wrapWidth.value = scrollRef.value!.wrapRef.offsetWidth
}
window.onresize = calcWrapWidth
onMounted(calcWrapWidth)
</script>

<template>
  <div
    ref="cdnCascaderEl"
    class="cdn-cascader"
  >
    <slot name="exit-fullscreen" />
    <div class="cdn-cascader__content">
      <res-scrollbar
        ref="scrollRef"
        :wrap-class="[
          'cdn-cascader__content--scrollbar',
          isFullscreen ? 'is-fullscreen' : '',
        ]"
      >
        <level-card
          v-for="region in dataSource?.charts || []"
          v-show="dataSource?.charts?.length"
          :key="region.region_id"
          :region="region"
          @node-click="node => emit('nodeClick', diff.length > 0, node)"
        />
        <div
          v-show="!dataSource?.charts?.length"
          class="min-h-600px w-full flex flex flex-1 flex-col items-center justify-center gap-y-2 bg-white !h-full"
        >
          <!-- <img
            src="@/assets/images/node-cascade-empty.png"
            width="80"
            height="80"
            alt="" /> -->
          <span class="text-sm/22px">节点暂未安装，请前往
            <span
              class="cursor-pointer text-primary"
              @click="$router.push({ name: 'CdnNodeNodeList' })"
            >节点列表</span>
            安装节点</span>
        </div>
      </res-scrollbar>
    </div>
  </div>
</template>
